""" post发送封装，增加了发送记录定时写入数据库的功能,只要配置对应的数据库连接即可，无需调用写数据库方法，如果不设置数据库连接，会自动写日志.
写数据库的数据库表字段定义
create table record(
    data varchar(max),  -- 发送的数据内容
    state varchar(100),  -- 返回的成功标志位内容
    stateinfo varchar(max),  -- 失败时记录所有的返回内容
    intername varchar(100),  -- 接口名称，默认为url
    url varchar(100),  -- 接口地址
    time datetime,  -- 时间，毫秒级别
    reposttimes int  -- 重发次数
)
"""
from plugin.db import MSsqlClient
from plugin.logger import MyLogger
from plugin.scheduler import scheduler_add_job, cron
from config import Config
import json
import datetime
import requests
import threading

__log = MyLogger.logger  # 日志记录对象
__conn: MSsqlClient = None  # 数据库连接
__flag: dict = {}  # 成功标志，对接中，发送成功时，对方返回的字段和内容
__interfaces: dict = {}  # 接口分类
__post_config = Config.module_config.post


def set_send_success_flag(flagname='message', flagvalue='success'):
    """ 设置发送成功的标志 """
    global __flag
    if not __flag or len(__flag) == 0:
        __flag['flagname'] = flagname
        __flag['flagbvalue'] = flagvalue


def set_dblink(**link):
    """ 设计数据库连接，用于将发送记录写入到数据库 """
    global __conn
    __conn = MSsqlClient(**link) if len(link.keys()) > 0 else None


set_dblink(__post_config.record_link)
__flag = json.loads(__post_config.flag)
set_send_success_flag(list(__flag.keys())[0], list(__flag.values())[0])


def post(datas, url, intername=None, tablename='record', logger=None):
    """
    发送数据记录
    @param:
        datas: 待发送数据
        url: 接口地址
        intername: default->url 接口类型名称，用于记录数据库后便于查询
        tablename: default->'record' 数据写入数据库时，存放数据的表名
        logger: default->Innerlog.log 日志记录，不同接口可能需要记录到不同的日志文件里面，这里支持传不同的日志对象
    """
    global __log, __interfaces
    __log = logger if logger else __log
    interface = None
    # 如果配置了数据库连接，并且有对应的表名，需要将发送记录写入数据库
    if tablename and __conn:
        intername = intername if intername else url
        if not __interfaces.__contains__(intername):
            interface = interface_type(intername, tablename, threading.RLock(), [])
            __interfaces[intername] = interface
            set_record_job(interface)
        else:
            interface = __interfaces[intername]
    _post(datas, url, interface)


class Record():
    """ 发送记录数据 """
    def __init__(self, data, state, stateinfo, intername, url, time=None, reposttimes=0) -> None:
        """
        @param:
            data: 发送的数据内容
            state: 发送的结果状态
            stateinfo: 失败时记录返回的全文本
            intername: 接口名称，如没有，默认是url
            url: 接口url
            time: 发送时间，字符串格式，毫秒级别
            reposttimes：重发次数，用于失败重发
        """
        self.data = data
        self.state = state
        self.stateinfo = stateinfo
        self.intername = intername
        self.url = url
        self.time = time if time else str(datetime.datetime.now())[:-3]
        self.reposttimes = reposttimes


class interface_type():
    """ 接口类型数据 """
    def __init__(self, typename, tablename, lock: threading.RLock, cache) -> None:
        """
        @param:
            typename: 接口类型
            tablename: 存储该类接口发送记录的表
            lock: 锁，用于读写同步
            cache: 缓存，发送记录临时存于这里，定时往数据库写
        """
        self.typename = typename
        self.tablename = tablename
        self.lock = lock
        self.cache = cache


def _post(datas, url, interface: interface_type):
    """
    post发送方法
    @param:
        datas: 待发送数据
        url: 接口地址
        interface: 接口数据类型，用于将已发送的数据记录下来
    """
    global __log
    records = []
    for data in datas:
        send_result = 'sendFail'  # 表示默认失败
        resp_text = ''  # 回复内容
        try:
            res = requests.post(data=data, url=url, timeout=(__post_config.timeout if __post_config.timeout else 10))
            send_result = json.loads(res.text)[__flag['flagname']]
        except Exception as e:
            __log.error('发送失败：')
            __log.error(data)
            if res and res.text:
                resp_text = res.text  # 失败时记录返回结果的全部内容
                __log.error(res.text)
            __log.error(e)
        record = Record(data, send_result, resp_text, url)
        records.append(record)
    # 加锁，记录发送数据及其结果，防止写数据库时干扰记录
    if interface and interface.lock:
        interface.lock.acquire()
        interface.cache.extend(records)
        interface.lock.release()
    else:
        # 不写数据库就写日志
        for _record in records:
            __log.debug("发送数据'{}'\n返回内容'{}'".format(_record.data, _record.send_result))


# 发送失败的列表
__send_fail_results = []


def __repost_record():
    if __conn:
        if len(__send_fail_results) > 1000:
            __conn.select('select top 1000 from ')


def record_into_db(inter: interface_type):
    """
    将记录写入数据库
    @param:
        inter: 接口数据类型
    """
    global __conn
    if __conn:
        inter.lock.acquire()
        records = inter.cache[:]
        inter.lock.release()
        __conn.insert_objects(records, inter.tablename)


__job_index = 0  # 任务id


def set_record_job(interface: interface_type):
    """
    设置将记录写入数据库的定时任务
    @param:
        interface: 接口数据类型
    """
    global __job_index
    index = __job_index % 30
    scheduler_add_job(record_into_db, cron(ss="{}".format(index * 2)), id=__job_index, **interface)
    __job_index += 1
